-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Babel MVP #143
Babel MVP #143
Conversation
@@ -0,0 +1,5 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in babel7 (soon-ish) it will be possible to use .babelrc.js
directly and therefore omit those .babelrc
entirely
packages/disposable/.babelrc.js
Outdated
}] | ||
], | ||
plugins: [ | ||
['transform-builtin-extend', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the custom plugin for extending built-ins - as mentioned above
package.json
Outdated
@@ -16,6 +16,26 @@ | |||
"author": "brian@hovercraftstudios.com", | |||
"license": "MIT", | |||
"devDependencies": { | |||
"lerna": "^2.1.2" | |||
"@briancavalier/assert": "^3.2.0", | |||
"babel-core": "^6.26.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ive hoisted all used packages to the root package.json
- according to lerna team this should result in faster bootstraps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I was under the impression that each package had to list its own deps and then use bootstrap --hoist
. This is much better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that each pkg should still lost its own deps, at least i treat lerna packages being in single repository just some kimd of implementation detail. Ideally i always want to keep them separate so the pkg's dir could copied/moved and still keep working without changes.
Also each pkg need to have its deps with executables listed so they can be linked properly and used from npm scripts
Gathering all deps in root package.json is an additional step which according to lerna docs (i think) allows lerna for faster bootstraps but i aint sure why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/lerna/lerna/blob/master/FAQ.md#root-packagejson
The root can also hold all the "hoisted" packages, which speeds up bootstrapping when using the --hoist flag.
package.json
Outdated
"babel-plugin-external-helpers": "^6.22.0", | ||
"babel-plugin-transform-builtin-extend": "^1.1.2", | ||
"babel-preset-env": "^1.6.0", | ||
"babel-preset-power-assert": "^1.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couldnt find if it was used before or if this is some leftover from the past, ive kept it for now but it seems this can be either removed or added to the used presets in prelude
package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Yes, we can get rid of it.
presets: [ | ||
['env', { | ||
modules, | ||
loose: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forceAllTransforms: true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was thinking about it, but aint sure if there is any benefit in that if we do not provide non-default targets, thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's same target like uplify
before. At least if defaults will be changed then nothing will be broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's same target like uplify before.
Just a confirmation - that's exactly what it is
At least if defaults will be changed then nothing will be broken.
Good point, gonna add this later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant semantically the same too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I understanding forceAllTransforms
correctly in that it essentially causes babel-preset-env
to behave like babel-preset-es2015
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda, its job is to output pure es5 which can be ofc understood by subsequent tools (like uglifyjs)
Preset2015 has only es2015 plugins in it, but preset-env has also plugins from other yearly presets and also it has (or soon it will, aint sure) shipped proposals plugins (like when browsers implement language features from stage 3 or something).
Better to merge this first |
Sure thing, I just didn't want to wait before creating a PR, when the other one gets merged in I'm gonna rebase this one. |
Dont worry, i knew it will be needed later from the very beginning, also shouldnt be particularly headache-y ;) |
Ok, I've rebased this PR, please keep in mind that this is not merge-ready, because of the usage of custom (non es5 compatible) |
hi @Andarist this is quite interesting setup you have here, is there anyway to compare the results of this setup to our current setup to see what wins we get? |
The diff can be seen here. Unfortunately it is not easily comparable. I've studied it for some time and mostly (haha 🤣) the difference is in class transform:
Ofc as mentioned above - ur original code style is lost in the output when using babel. |
any examples of bundle size comparisons ? |
Sure - I can check them out and report back later, but diffs will be a little bit off, because a PR is not finished due to the issues described regarding class transform. I always measure such things by inspecting minified+gziped UMD bundles, is that ok or should I measure in some other way? |
I think that would be nice to see you could use https://github.com/mostjs/core/tree/master/examples/counter as a way to compare |
@Andarist Yep, that'd be just fine. Thank you for all your work on this so far! Looking forward to seeing size comparisons. |
Ping @Andarist. We're definitely still interested in seeing a size comparison. Is there anything else we can do to help? |
Nah, not really - I will send comparisons as soon as I can, just couldn't focus at this PR lately as I had some other issues to tackle on. |
Thanks @Andarist. No worries 😄 |
All results for UMD minified and gzipped bundles
Difference is there, although quite small and as I've written before - alternative class transform should be written before merging this in, which potentially could decrease the those size differences. I've also noticed that only the |
@Andarist Whew! Now that 1.0 is released, I'm going to spend some time on this. My plan is to build https://github.com/mostjs/core/tree/master/examples/counter using master and this branch so we can see the size difference in an application. Granted, it's a trivial application, but I think that's a good place to start since it should result in a fairly large size difference (at least, I think it should!). If it does then I think we'll feel good about moving ahead. |
Recent versions of rollup might be able to tree-shake some The experiment should use webpack with ModuleConcatenationPlugin on and uglifyjs, those settings should give better tree-shaking results - webpack alone actually has quite poor algorithm for this stuff. I will try to rebase the branch a little bit later. |
I made a couple local branches, one based on this PR branch (rebased to latest master), and one based on latest master. Both add Here are the results with just uglify, and with uglify+gzip:
The savings are quite significant. Again, this is for a trivial app that uses a tiny amount of the total API surface area. Obviously, an app that uses more of the API will see less of a savings ... but that's the whole point: You get exactly what you opt into, and no more. This seems compelling enough to me to proceed, but I'd love to hear everyone else's thoughts. |
@Andarist Ok, thanks for the info about recent rollup. I'll try to run the experiment again with the latest version and post more results. We should do a similar test with webpack. The savings are probably less, but its worth seeing. I have to switch to day job mode now, but I'll push my branches when I have a chance in case anyone else wants to experiment. |
And there we go. Next, I'm going to try to get rid of the need for extending Error. I'll do that in another PR so we can all see what it looks like before making a decision about it. |
👍 that would be a breaking change though, wouldnt it? |
I think it depends on exactly what we do. The particular error thrown by |
Then both options seems fine to me, certainly better to use prototypal inheritance for a single use case than adding an additional (somewhat) complex plugin. If you follow that path it's advised to use IIFE to output a class into a single variable. |
Personally I like 1st better, seems like a cleaner change and being more straightforward about its purpose. I'd only change it to: export const DisposeAllError = (Error => {
function DisposeAllError(message, errors) {
Error.call(this, message)
this.message = message
this.name = DisposeAllError.name
this.errors = errors
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DisposeAllError)
}
this.stack = `${this.stack}${formatErrorStacks(this.errors)}`
}
DisposeAllError.prototype = Object.create(Error.prototype)
return DisposeAllError
})(Error) |
@Andarist Agreed about the first option. What's the reason for the IIFE in this particular case? It's not clear to me what it's defending against. |
Having this in top level scope: DisposeAllError.prototype = Object.create(Error.prototype) will prevent tree-shaking of |
Ah, ok, thanks for explaining. I'll add the IIFE. |
Ok, there we go: 1019bda Do you want me to cherry pick that onto this branch, and remove the babel plugin? |
Yeah 👍 that would simplify working with this branch :) |
Done! Cherry-picked prototypal inheritance and removed builtin-extend plugin on this branch. |
Cool! This PR is ready to merge then, if you want to proceed with it. Let me know if it needs any other adjustments. |
Here are results with webpack:
25121 / 42553 = ~59% of original non-gzip And here's the webpack config I used: const path = require('path')
const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './counter/src/index.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'counter/dist')
},
resolve: {
mainFields: [ 'module', 'jsnext:main', 'browser', 'main' ]
},
devtool: 'source-map',
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new UglifyJSPlugin()
]
} |
I pushed the two branches I used for the tests. Be sure to test without PURE: https://github.com/mostjs/core/tree/x-webpack-tree-shake-master |
Cool comparisons! Would be good to test webpack without |
Without ModuleConcatenationPlugin (See
webpack config: const path = require('path')
// const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './counter/src/index.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'counter/dist')
},
resolve: {
mainFields: [ 'module', 'jsnext:main', 'browser', 'main' ]
},
devtool: 'source-map',
plugins: [
// new webpack.optimize.ModuleConcatenationPlugin(),
new UglifyJSPlugin()
]
} |
@Andarist Huge thanks for starting the conversation in #138 and for this PR. @TrySound, thank you as well for the help and discussion. I'm having a real "this is why open source is awesome" moment right now about the awesome collaboration 😄 ... and I'm excited that we'll be able to release such a concrete improvement for I'm gonna go through the diff one last time to make sure we've tied up all loose ends. |
Actually results are similar because you are producing a flat bundle 👏 If you'd transpile file by file and produce a "mirror" directory structure results would be a lot worse probably and that would be exposed even more by inspecting a "trivial app" because in such a trivial app tree shaking should do more than for more complex app which would probably use a lot more of the core and thus benefits would be smaller.
Thanks for kind words :) I have just explored this area quite a bit lately and observed what prevents and what not tree shaking algos, so I've looked on several libs and tried to improve the situation where I could |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dynamite work 😍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having checked the builds, this LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
Just published |
Proof of concept for #140 (comment)
Not yet ready to merge!
Extending an
Error
is an issue for babel - had to add for the time being custom transform for this. It's always possible to write buble-like class transform, shouldnt be a problem at all.It should be easy to compare outputs (before and after) and discuss differences as you guys create "flat bundles" for the distribution